﻿namespace Pathfinder.Base.UI
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Windows.Controls;
    using Bridge.Objects;
    using Bridge.UI.Utilities;
    using Pathfinder.Base.Constructs;

    public class PathfinderCharacterView : CharacterView<PathfinderCharacter>
    {
        public PathfinderCharacterView(PathfinderCharacter character)
            : base(character)
        {
            mPathfinderCharacter = character;
            mEditCharacterUserControl = new EditPathfinderCharacter(this);

            List<ACType> normalACTypes = new List<ACType>((ACType[])Enum.GetValues(typeof(ACType)));
            foreach (var ac in character.AC)
            {
                ACTypeEffectAttribute acTypeEffectAttribute = ac.Key.GetCustomAttribute<ACTypeEffectAttribute>();
                if (acTypeEffectAttribute == null || !acTypeEffectAttribute.Dependent)
                {
                    mArmorClassViews.Add(new ArmorClassView(ac.Key, new ObservableCollection<ACType>(normalACTypes), ac.Value, this));
                }
            }
            RefreshACLists();

            List<UIEnumView<SpeedType>> normalSpeedTypes = new List<UIEnumView<SpeedType>>(GetUIEnumViews<SpeedType>());
            List<UIEnumView<DRType>> normalDRTypes = new List<UIEnumView<DRType>>(GetUIEnumViews<DRType>());
            List<UIEnumView<ERType>> normalERTypes = new List<UIEnumView<ERType>>(GetUIEnumViews<ERType>());
            List<UIEnumView<SightType>> normalSightTypes = new List<UIEnumView<SightType>>(GetUIEnumViews<SightType>());

            foreach (var speed in character.Speed)
            {
                mSpeedViews.Add(new EnumInfoView<SpeedType>(speed.Key, speed.Value, new ObservableCollection<UIEnumView<SpeedType>>(normalSpeedTypes), this));
            }
            foreach (var dr in character.DR)
            {
                mDRViews.Add(new EnumInfoView<DRType>(dr.Key, dr.Value, new ObservableCollection<UIEnumView<DRType>>(normalDRTypes), this));
            }
            foreach (var er in character.ER)
            {
                mERViews.Add(new EnumInfoView<ERType>(er.Key, er.Value, new ObservableCollection<UIEnumView<ERType>>(normalERTypes), this));
            }
            foreach (var sight in character.Sight)
            {
                mSightViews.Add(new EnumInfoView<SightType>(sight.Key, sight.Value, new ObservableCollection<UIEnumView<SightType>>(normalSightTypes), this));
            }
            foreach (var alignment in GetUIEnumViews<Alignment>())
            {
                mAlignmentViews.Add(alignment);
            }
            NotifyPropertyChanged("Alignments");
            NotifyPropertyChanged("Alignment");

            RefreshList<SpeedType>(Character.Speed, mSpeedViews);
            RefreshList<DRType>(Character.DR, mDRViews);
            RefreshList<ERType>(Character.ER, mERViews);
            RefreshList<SightType>(Character.Sight, mSightViews);
        }

        public override string Name
        {
            get { return Character.Name; }
        }

        public override int CurrentHP
        {
            get { return Character.CurrentHitPoints; }
        }

        public override int MaxHP
        {
            get { return Character.MaximumHitPoints; }
        }

        public override UserControl EditCharacterUserControl
        {
            get { return mEditCharacterUserControl; }
        }

        public PathfinderCharacter PathfinderCharacter
        {
            get { return mPathfinderCharacter;  }
        }

        public ObservableCollection<ArmorClassView> ArmorClassViews
        {
            get { return mArmorClassViews; }
        }

        public ObservableCollection<EnumInfoView<DRType>> DRViews
        {
            get { return mDRViews; }
        }

        public ObservableCollection<EnumInfoView<ERType>> ERViews
        {
            get { return mERViews; }
        }

        public ObservableCollection<EnumInfoView<SightType>> SightViews
        {
            get { return mSightViews; }
        }

        public ObservableCollection<EnumInfoView<SpeedType>> SpeedViews
        {
            get { return mSpeedViews; }
        }

        public ObservableCollection<UIEnumView<Alignment>> Alignments
        {
            get { return mAlignmentViews; }
        }

        public UIEnumView<Alignment> Alignment
        {
            get
            {
                foreach (var alignment in Alignments)
                {
                    if (alignment.Value.Equals(Character.Alignment))
                    {
                        return alignment;
                    }
                }
                return null;
            }
            set
            {
                Character.Alignment = value.Value;
                NotifyPropertyChanged("Alignment");
            }
        }


        public void ChangeAC(ACType oldAcType, ACType newAcType, int newAcNumber)
        {
            mPathfinderCharacter.RemoveAC(oldAcType);
            mPathfinderCharacter.AddAC(newAcType, newAcNumber);
            RefreshACLists();
        }

        public void AddAC(ACType newAcType)
        {
            mPathfinderCharacter.AddAC(newAcType, 0);
            mArmorClassViews.Add(new ArmorClassView(
                newAcType,
                new ObservableCollection<ACType>((ACType[])Enum.GetValues(typeof(ACType))),
                0,
                this));
            RefreshACLists();
        }

        public void RemoveAC(ACType acType)
        {
            mPathfinderCharacter.RemoveAC(acType);
            List<ArmorClassView> removeViews = new List<ArmorClassView>();
            foreach (ArmorClassView armorClassView in ArmorClassViews)
            {
                if (armorClassView.ACType == acType)
                {
                    removeViews.Add(armorClassView);
                }
            }
            foreach (ArmorClassView armorClassView in removeViews)
            {
                ArmorClassViews.Remove(armorClassView);
            }
        }

        public List<UIEnumView<T>> GetUIEnumViews<T>()
        {
            List<UIEnumView<T>> returnList = new List<UIEnumView<T>>();
            foreach (T enumValue in Enum.GetValues(typeof(T)))
            {
                returnList.Add(new UIEnumView<T>(enumValue));
            }
            return returnList;
        }

        public void Add<T>(T value)
        {
            Enum actualValue = value as Enum;
            if (value is DRType)
            {
                Character.AddDR((DRType)actualValue, 0);
                mDRViews.Add(new EnumInfoView<DRType>((DRType)actualValue, 0, new ObservableCollection<UIEnumView<DRType>>(GetUIEnumViews<DRType>()), this));
                RefreshList<DRType>(Character.DR, mDRViews);
            }
            else if (value is ERType)
            {
                Character.AddER((ERType)actualValue, 0);
                mERViews.Add(new EnumInfoView<ERType>((ERType)actualValue, 0, new ObservableCollection<UIEnumView<ERType>>(GetUIEnumViews<ERType>()), this));
                RefreshList<ERType>(Character.ER, mERViews);
            }
            else if (value is SightType)
            {
                Character.AddSight((SightType)actualValue, 30);
                mSightViews.Add(new EnumInfoView<SightType>((SightType)actualValue, 0, new ObservableCollection<UIEnumView<SightType>>(GetUIEnumViews<SightType>()), this));
                RefreshList<SightType>(Character.Sight, mSightViews);
            }
            else if (value is SpeedType)
            {
                Character.AddSpeed((SpeedType)actualValue, 30);
                mSpeedViews.Add(new EnumInfoView<SpeedType>((SpeedType)actualValue, 0, new ObservableCollection<UIEnumView<SpeedType>>(GetUIEnumViews<SpeedType>()), this));
                RefreshList<SpeedType>(Character.Speed, mSpeedViews);
            }
        }

        public void Remove<T>(T value)
        {
            Enum actualValue = value as Enum;
            if (value is DRType)
            {
                Character.RemoveDR((DRType)actualValue);
                RemoveViews<DRType>((DRType)actualValue, ref mDRViews);
                RefreshList<DRType>(Character.DR, mDRViews);
            }
            else if (value is ERType)
            {
                Character.RemoveER((ERType)actualValue);
                RemoveViews<ERType>((ERType)actualValue, ref mERViews);
                RefreshList<ERType>(Character.ER, mERViews);
            }
            else if (value is SightType)
            {
                Character.RemoveSight((SightType)actualValue);
                RemoveViews<SightType>((SightType)actualValue, ref mSightViews);
                RefreshList<SightType>(Character.Sight, mSightViews);
            }
            else if (value is SpeedType)
            {
                Character.RemoveSpeed((SpeedType)actualValue);
                RemoveViews<SpeedType>((SpeedType)actualValue, ref mSpeedViews);
                RefreshList<SpeedType>(Character.Speed, mSpeedViews);
            }
        }

        

        public void Change<T>(T oldValue, T newValue, int newRange)
        {
            Enum actualOldValue = oldValue as Enum;
            Enum actualNewValue = newValue as Enum;
            if (actualOldValue is DRType)
            {
                Character.RemoveDR((DRType)actualOldValue);
                Character.AddDR((DRType)actualNewValue, newRange);
                RefreshList<DRType>(Character.DR, mDRViews);
            }
            else if (actualOldValue is ERType)
            {
                Character.RemoveER((ERType)actualOldValue);
                Character.AddER((ERType)actualNewValue, newRange);
                RefreshList<ERType>(Character.ER, mERViews);
            }
            else if (actualOldValue is SightType)
            {
                Character.RemoveSight((SightType)actualOldValue);
                Character.AddSight((SightType)actualNewValue, newRange);
                RefreshList<SightType>(Character.Sight, mSightViews);
            }
            else if (actualOldValue is SpeedType)
            {
                Character.RemoveSpeed((SpeedType)actualOldValue);
                Character.AddSpeed((SpeedType)actualNewValue, newRange);
                RefreshList<SpeedType>(Character.Speed, mSpeedViews);
            }
        }

        public void Set<T>(T value, int newRange)
        {
            Enum actualValue = value as Enum;
            if (value is DRType)
            {
                Character.SetDR((DRType)actualValue, newRange);
            }
            else if (value is ERType)
            {
                Character.SetER((ERType)actualValue, newRange);
            }
            else if (value is SightType)
            {
                Character.SetSight((SightType)actualValue, newRange);
            }
            else if (value is SpeedType)
            {
                Character.SetSpeed((SpeedType)actualValue, newRange);
            }
        }

        private EditPathfinderCharacter mEditCharacterUserControl;
        private PathfinderCharacter mPathfinderCharacter;
        private ObservableCollection<ArmorClassView> mArmorClassViews = new ObservableCollection<ArmorClassView>();
        private ObservableCollection<EnumInfoView<DRType>> mDRViews = new ObservableCollection<EnumInfoView<DRType>>();
        private ObservableCollection<EnumInfoView<ERType>> mERViews = new ObservableCollection<EnumInfoView<ERType>>();
        private ObservableCollection<EnumInfoView<SightType>> mSightViews = new ObservableCollection<EnumInfoView<SightType>>();
        private ObservableCollection<EnumInfoView<SpeedType>> mSpeedViews = new ObservableCollection<EnumInfoView<SpeedType>>();
        private ObservableCollection<UIEnumView<Alignment>> mAlignmentViews = new ObservableCollection<UIEnumView<Alignment>>();

        private void RefreshACLists()
        {
            List<ACType> normalACTypes = new List<ACType>((ACType[])Enum.GetValues(typeof(ACType)));
            List<ACType> sortedAcTypes = new List<ACType>();
            foreach (ACType acType in normalACTypes)
            {
                ACTypeEffectAttribute acTypeEffectAttribute = acType.GetCustomAttribute<ACTypeEffectAttribute>();
                if (acTypeEffectAttribute == null || !acTypeEffectAttribute.Dependent)
                {
                    sortedAcTypes.Add(acType);
                }
            }

            foreach (var ac in mPathfinderCharacter.AC)
            {
                if (sortedAcTypes.Contains(ac.Key))
                {
                    sortedAcTypes.Remove(ac.Key);
                }
            }
            sortedAcTypes.Sort(new Comparison<ACType>((acType, otherAcType) => acType.ToString().CompareTo(otherAcType.ToString())));

            foreach (var ac in mPathfinderCharacter.AC)
            {
                ACTypeEffectAttribute acTypeEffectAttribute = ac.Key.GetCustomAttribute<ACTypeEffectAttribute>();
                if (acTypeEffectAttribute == null || !acTypeEffectAttribute.Dependent)
                {
                    List<ACType> acTypes = new List<ACType>(sortedAcTypes);
                    acTypes.Add(ac.Key);
                    acTypes.Sort(new Comparison<ACType>((acType, otherAcType) => acType.ToString().CompareTo(otherAcType.ToString())));
                    foreach (ArmorClassView armorClassView in mArmorClassViews)
                    {
                        if (armorClassView.ACType == ac.Key)
                        {
                            armorClassView.PossibleACs = new ObservableCollection<ACType>(acTypes);
                        }
                    }
                }
            }
        }

        private void RefreshList<T>(Dictionary<T, int> inputList, ObservableCollection<EnumInfoView<T>> inputViews)
        {
            List<T> normalSightTypes = new List<T>((T[])Enum.GetValues(typeof(T)));
            List<UIEnumView<T>> uiEnumViews = new List<UIEnumView<T>>();

            foreach (var value in inputList)
            {
                if (normalSightTypes.Contains(value.Key))
                {
                    normalSightTypes.Remove(value.Key);
                }
            }
            foreach (T valueType in normalSightTypes)
            {
                uiEnumViews.Add(new UIEnumView<T>(valueType));
            }

            foreach (var value in inputList)
            {
                List<UIEnumView<T>> valueTypes = new List<UIEnumView<T>>(uiEnumViews);
                valueTypes.Add(new UIEnumView<T>(value.Key));
                valueTypes.Sort(new Comparison<UIEnumView<T>>((valueType, otherAcType) => valueType.ToString().CompareTo(otherAcType.ToString())));
                foreach (EnumInfoView<T> valueView in inputViews)
                {
                    if (valueView.Value.Equals(value.Key))
                    {
                        valueView.PossibleValues = new ObservableCollection<UIEnumView<T>>(valueTypes);
                    }
                }
            }
        }

        private void RemoveViews<T>(T value, ref ObservableCollection<EnumInfoView<T>> list)
        {
            List<EnumInfoView<T>> removeViews = new List<EnumInfoView<T>>();
            foreach (var findValue in list)
            {
                if (findValue.Value.Equals(value))
                {
                    removeViews.Add(findValue);
                }
            }
            foreach (var removeValue in removeViews)
            {
                list.Remove(removeValue);
            }
        }
    }
}
